package com.isp.common.web.utils;

import com.alibaba.excel.util.StringUtils;
import com.isp.common.utils.JacksonUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author linsy
 * @created 2024/7/27
 */
public class DingNoticeUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(DingNoticeUtils.class);

    private final static Integer SUCCESS_CODE = 200;
    private final static String DEFAULT_URL = "https://oapi.dingtalk.com/robot/send?access_token=41b2374130fb0a178f4aaf0d5db2369facd30471f075e837c32a45fd47174cf9";
    private final static String DEFAULT_SECRET = "SEC38d99d55125627561b0a2d2dd213c03b12328cf80f43503956cfa9e612f65400";

    public static void main(String[] args) {
        String content = "环境：dev\n" +
                "工程：product-common-be\n" +
                "类型：通知\n" +
                "消息：测试业务通知\n";
        sendDingWarningMsg(content, null, null);
    }

    /**
     * 钉钉发送业务
     * 如果需要@所有人，mobileList传空或空集合
     *
     * @param content    发送内容
     * @param mobileList 指定通知人手机号
     * @param url        钉钉机器人地址。null为默认地址
     * @param secretKey  密钥。null为默认机器人密钥
     */
    public static String sendDingWarningMsg(String content, List<String> mobileList, String url, String secretKey) {
        AtDingMessage message = new AtDingMessage();

        Long timestamp = System.currentTimeMillis();
        String secret = StringUtils.isBlank(secretKey) ? DEFAULT_SECRET : secretKey;
        String sign = getSign(timestamp, secret);

        if (StringUtils.isBlank(sign)) {
            return null;
        }

        Map<String, String> paramContent = new HashMap<>(2);
        paramContent.put("content", content);
        message.setText(paramContent);
        AtBean atBean = new AtBean();
        if (mobileList == null || mobileList.isEmpty()) {
            atBean.setAtAll(true);
        } else {
            atBean.setAtMobiles(mobileList);
        }
        message.setAt(atBean);
        final String dingUrl = StringUtils.isBlank(url) ? DEFAULT_URL : url;
        return doPost(dingUrl + "&timestamp=" + timestamp + "&sign=" + sign, JacksonUtils.toJsonString(message));
    }

    /**
     * 钉钉发送业务(不需要@人)
     *
     * @param content   发送内容
     * @param url       钉钉机器人地址。null为默认地址
     * @param secretKey 密钥。null为默认机器人密钥
     */
    public static String sendDingWarningMsg(String content, String url, String secretKey) {
        DingMessage message = new DingMessage();

        Long timestamp = System.currentTimeMillis();
        String secret = StringUtils.isBlank(secretKey) ? DEFAULT_SECRET : secretKey;
        String sign = getSign(timestamp, secret);

        if (StringUtils.isBlank(sign)) {
            return null;
        }

        Map<String, String> paramContent = new HashMap<>(2);
        paramContent.put("content", content);
        message.setText(paramContent);
        final String dingUrl = StringUtils.isBlank(url) ? DEFAULT_URL : url;
        return doPost(dingUrl + "&timestamp=" + timestamp + "&sign=" + sign, JacksonUtils.toJsonString(message));
    }


    private static String doPost(String urlStr, String param) {
        OutputStreamWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        HttpURLConnection conn;
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            //发送POST请求必须设置为true
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //设置连接超时时间和读取超时时间
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(10000);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Accept", "application/json");

            //获取输出流
            out = new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8);
            LOGGER.info(param);
            out.write(param);
            out.flush();
            out.close();
            //取得输入流，并使用Reader读取
            if (SUCCESS_CODE == conn.getResponseCode()) {
                in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
                String line;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                }
            } else {
                LOGGER.error("ResponseCode is an error code:" + conn.getResponseCode());
            }
        } catch (Exception e) {
            LOGGER.error("发送钉钉消息异常", e);
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ioe) {
                LOGGER.error("关闭资源异常", ioe);
                ioe.printStackTrace();
            }
        }
        return result.toString();
    }

    public static String getSign(Long timestamp, String secret) {
        try {
            String stringToSign = timestamp + "\n" + secret;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
            return URLEncoder.encode(new String(Base64.encodeBase64(signData), StandardCharsets.UTF_8), "UTF-8");
        } catch (Exception e) {
            LOGGER.error("发送钉钉消息验签失败，{}", e.getMessage(), e);
            return null;
        }
    }
}

class DingMessage {
    private Map<String, String> text;
    private String msgtype;

    {
        this.msgtype = "text";
    }

    public DingMessage(Map<String, String> text, String msgtype) {
        this.text = text;
        this.msgtype = msgtype;
    }

    public Map<String, String> getText() {
        return text;
    }

    public void setText(Map<String, String> text) {
        this.text = text;
    }

    public String getMsgtype() {
        return msgtype;
    }

    public void setMsgtype(String msgtype) {
        this.msgtype = msgtype;
    }

    public DingMessage() {
    }
}

class AtDingMessage extends DingMessage {

    private AtBean at;

    public AtDingMessage() {
    }

    public AtDingMessage(AtBean at) {
        this.at = at;
    }

    public AtBean getAt() {
        return at;
    }

    public void setAt(AtBean at) {
        this.at = at;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AtDingMessage that = (AtDingMessage) o;
        return Objects.equals(at, that.at);
    }

    @Override
    public int hashCode() {
        return Objects.hash(at);
    }
}

class AtBean {
    private Boolean isAtAll;
    private List<String> atMobiles;

    public AtBean() {
    }

    public AtBean(Boolean isAtAll, List<String> atMobiles) {
        this.isAtAll = isAtAll;
        this.atMobiles = atMobiles;
    }

    public Boolean getAtAll() {
        return isAtAll;
    }

    public void setAtAll(Boolean atAll) {
        isAtAll = atAll;
    }

    public List<String> getAtMobiles() {
        return atMobiles;
    }

    public void setAtMobiles(List<String> atMobiles) {
        this.atMobiles = atMobiles;
    }
}